package remoting

import (
	"bbq/common/protocol/remoteCommand"
	"github.com/panjf2000/gnet"
	"github.com/panjf2000/gnet/pkg/pool/goroutine"
)

type GnetRemoteBase struct {
	*gnet.EventServer

	responseTable map[int64]*ResponseFuture

	pool *goroutine.Pool

	processorTable map[int16]GnetRequestProcessor
}

func newGnetRemoteBase() *GnetRemoteBase {
	instance := &GnetRemoteBase{
		responseTable:  make(map[int64]*ResponseFuture, 256),
		processorTable: make(map[int16]GnetRequestProcessor),
		pool:           goroutine.Default(),
	}

	return instance
}

/*
 * 注册处理器
 */
func (rs *GnetRemoteBase) RegisterProcessor(code int16, processor GnetRequestProcessor, executor *goroutine.Pool) {
	rs.processorTable[code] = processor
}

func (ts *GnetRemoteBase) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	ts.processMessageReceived(c, frame)
	return
}

//处理消息
func (ts *GnetRemoteBase) processMessageReceived(conn gnet.Conn, frame []byte) {
	data := append([]byte{}, frame...)
	cmd := remoteCommand.Decode(data)

	if cmd != nil {
		switch cmd.GetType() {
		case remoteCommand.REQUEST_COMMAND:
			ts.processRequestCommand(conn, cmd)
		case remoteCommand.RESPONSE_COMMAND:
			ts.processResponseCommand(conn, cmd)
		default:
		}
	}
}

func (ts *GnetRemoteBase) processRequestCommand(conn gnet.Conn, cmd *remoteCommand.RemoteCommand) {
	// Use ants pool to unblock the event-loop.
	_ = ts.pool.Submit(func() {
		processor := ts.processorTable[cmd.Header.Code]
		responseCmd := processor.ProcessRequest(conn, cmd)

		responseCmd.Header.Opaque = cmd.Header.Opaque
		responseCmd.MarkResponseType()

		_ = conn.AsyncWrite(responseCmd.Encode())
	})
}

func (ts *GnetRemoteBase) processResponseCommand(conn gnet.Conn, cmd *remoteCommand.RemoteCommand) {
	opaque := cmd.Header.Opaque

	responseFuture := ts.responseTable[opaque]
	if responseFuture != nil {
		delete(ts.responseTable, opaque)
		responseFuture.PutResponse(cmd)
	}
}
